<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div><h1 id="node-js-">Node.js中的网络编程</h1>
<h2 id="labdoc-header-0">一、实验介绍</h2>
<h3 id="labdoc-header-1">1.1 实验内容</h3>
<p>此实验主要讲解TCP和UDP的网络编程，net模块提供了一个异步网络包装器，用于TCP网络编程，它包含了创建服务器和客户端的方法。dgram模块用于UDP网络编程。</p><h3 id="labdoc-header-2">1.2 实验知识点</h3>
<ul>
<li>网络编程的基本概念</li>
<li><code>net</code>模块的使用</li>
<li><code>dgram</code>模块的使用</li>
</ul>
<h3 id="labdoc-header-3">1.3 实验环境</h3>
<ul>
<li>Xfce终端</li>
<li>Node.js v4.2.1</li>
<li>gedit/vim：文本编辑</li>
</ul>
<h2 id="labdoc-header-4">二、实验步骤</h2>
<h3 id="labdoc-header-5">2.1 TCP Server</h3>
<p>net模块通过<code>net.createServer</code>方法创建TCP服务器，通过<code>net.connect</code>方法创建客户端去连接服务器。</p><p>通过net模块创建一个TCP Server：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// server.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> net = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'net'</span></span>);

<span class="hljs-comment"><span class="hljs-comment">// 创建TCP服务器</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = net.createServer(<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">socket</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'client connected'</span></span>);

    <span class="hljs-comment"><span class="hljs-comment">// 监听客户端的数据</span></span>
    socket.on(<span class="hljs-string"><span class="hljs-string">'data'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">data</span></span></span><span class="hljs-function">) </span></span>{
        <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'server got data from client: '</span></span>, data.toString());
    });
    <span class="hljs-comment"><span class="hljs-comment">// 监听客户端断开连接事件</span></span>
    socket.on(<span class="hljs-string"><span class="hljs-string">'end'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">data</span></span></span><span class="hljs-function">) </span></span>{
        <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'connection closed'</span></span>);
    });
    <span class="hljs-comment"><span class="hljs-comment">// 发送数据给客户端</span></span>
    socket.write(<span class="hljs-string"><span class="hljs-string">'Hello\r\n'</span></span>);
});

<span class="hljs-comment"><span class="hljs-comment">// 启动服务</span></span>
server.listen(<span class="hljs-number"><span class="hljs-number">8080</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'server bound'</span></span>);
});
</code></pre><p>然后再创建一个客户端：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// client.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> net = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'net'</span></span>);

<span class="hljs-comment"><span class="hljs-comment">// 连接服务器</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> client = net.connect({<span class="hljs-attr"><span class="hljs-attr">port</span></span>: <span class="hljs-number"><span class="hljs-number">8080</span></span>}, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'connected to server'</span></span>);
    client.write(<span class="hljs-string"><span class="hljs-string">'World!\r\n'</span></span>);
});

<span class="hljs-comment"><span class="hljs-comment">// 接收服务端的数据</span></span>
client.on(<span class="hljs-string"><span class="hljs-string">'data'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">data</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'client got data from server: '</span></span>, data.toString());
    <span class="hljs-comment"><span class="hljs-comment">// 断开连接</span></span>
    client.end();
});

<span class="hljs-comment"><span class="hljs-comment">// 断开连接</span></span>
client.on(<span class="hljs-string"><span class="hljs-string">'end'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'disconnected from server'</span></span>);
});

</code></pre><p>运行测试：</p><p>在虚拟机中打开两个终端，先运行TCP服务器代码：</p><pre><code class="hljs ruby">$ <span class="hljs-keyword">node</span> <span class="hljs-title">server</span>.js
</code></pre><p>然后在另一个终端运行TCP客户端代码：</p><pre><code class="hljs ruby">$ <span class="hljs-keyword">node</span> <span class="hljs-title">client</span>.js
</code></pre><p>即可看到两个终端运行结果。</p><h3 id="labdoc-header-6">2.2 简易聊天室服务端</h3>
<p>了解了基础的东西，下面我们来做一个简单的聊天室吧。</p><p>首先创建TCP服务器，和前面一样：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// chatServer.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> net = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'net'</span></span>);

<span class="hljs-comment"><span class="hljs-comment">// 创建TCP服务器</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = net.createServer();

server.on(<span class="hljs-string"><span class="hljs-string">'error'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">err</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server error: '</span></span>, err.message);
});

server.on(<span class="hljs-string"><span class="hljs-string">'close'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server closed'</span></span>);
});

server.listen(<span class="hljs-number"><span class="hljs-number">8080</span></span>);
</code></pre><p>接收客户端连接请求：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// chatServer.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> net = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'net'</span></span>);

<span class="hljs-comment"><span class="hljs-comment">// 创建TCP服务器</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = net.createServer();

<span class="hljs-comment"><span class="hljs-comment">// 新增的代码</span></span>
server.on(<span class="hljs-string"><span class="hljs-string">'connection'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">socket</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Got a new connection'</span></span>);
});

server.on(<span class="hljs-string"><span class="hljs-string">'error'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">err</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server error: '</span></span>, err.message);
});

server.on(<span class="hljs-string"><span class="hljs-string">'close'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server closed'</span></span>);
});

server.listen(<span class="hljs-number"><span class="hljs-number">8080</span></span>);
</code></pre><p>获取客户端发送过来的数据：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// chatServer.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> net = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'net'</span></span>);

<span class="hljs-comment"><span class="hljs-comment">// 创建TCP服务器</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = net.createServer();

server.on(<span class="hljs-string"><span class="hljs-string">'connection'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">socket</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Got a new connection'</span></span>);
    <span class="hljs-comment"><span class="hljs-comment">// 新增的代码</span></span>
    socket.on(<span class="hljs-string"><span class="hljs-string">'data'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">data</span></span></span><span class="hljs-function">) </span></span>{
        <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Got data: '</span></span>, data.toString());
    });
});

server.on(<span class="hljs-string"><span class="hljs-string">'error'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">err</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server error: '</span></span>, err.message);
});

server.on(<span class="hljs-string"><span class="hljs-string">'close'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server closed'</span></span>);
});

server.listen(<span class="hljs-number"><span class="hljs-number">8080</span></span>);
</code></pre><p>既然是聊天室，当然允许多个客户端用户同时连接，所以需要接收所有的用户连接：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// chatServer.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> net = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'net'</span></span>);

<span class="hljs-comment"><span class="hljs-comment">// 创建TCP服务器</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = net.createServer();
<span class="hljs-comment"><span class="hljs-comment">// 新增的代码</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> sockets = []; <span class="hljs-comment"><span class="hljs-comment">// 存储所有客户端socket</span></span>

server.on(<span class="hljs-string"><span class="hljs-string">'connection'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">socket</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Got a new connection'</span></span>);

    <span class="hljs-comment"><span class="hljs-comment">// 新增的代码</span></span>
    sockets.push(socket);

    socket.on(<span class="hljs-string"><span class="hljs-string">'data'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">data</span></span></span><span class="hljs-function">) </span></span>{
        <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Got data: '</span></span>, data);
    });
});

server.on(<span class="hljs-string"><span class="hljs-string">'error'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">err</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server error: '</span></span>, err.message);
});

server.on(<span class="hljs-string"><span class="hljs-string">'close'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server closed'</span></span>);
});

server.listen(<span class="hljs-number"><span class="hljs-number">8080</span></span>);
</code></pre><p>服务器广播数据，把来自客户端的数据转发送给其他所有客户端：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// chatServer.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> net = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'net'</span></span>);

<span class="hljs-comment"><span class="hljs-comment">// 创建TCP服务器</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = net.createServer();
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> sockets = []; <span class="hljs-comment"><span class="hljs-comment">// 存储所有客户端socket</span></span>

server.on(<span class="hljs-string"><span class="hljs-string">'connection'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">socket</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Got a new connection'</span></span>);

    sockets.push(socket);

    socket.on(<span class="hljs-string"><span class="hljs-string">'data'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">data</span></span></span><span class="hljs-function">) </span></span>{
        <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Got data: '</span></span>, data);

        <span class="hljs-comment"><span class="hljs-comment">// 新增代码</span></span>
        sockets.forEach(<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">otherSocket</span></span></span><span class="hljs-function">) </span></span>{
            <span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (otherSocket !== socket) {
                otherSocket.write(data);
            }
        });
    });
});

server.on(<span class="hljs-string"><span class="hljs-string">'error'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">err</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server error: '</span></span>, err.message);
});

server.on(<span class="hljs-string"><span class="hljs-string">'close'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server closed'</span></span>);
});

server.listen(<span class="hljs-number"><span class="hljs-number">8080</span></span>);
</code></pre><p>最后，需要把关闭连接的客户端从服务器广播列表中给删除掉：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// chatServer.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> net = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'net'</span></span>);

<span class="hljs-comment"><span class="hljs-comment">// 创建TCP服务器</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = net.createServer();
<span class="hljs-comment"><span class="hljs-comment">// 存储所有客户端socket</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> sockets = [];

server.on(<span class="hljs-string"><span class="hljs-string">'connection'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">socket</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Got a new connection'</span></span>);

    sockets.push(socket);

    socket.on(<span class="hljs-string"><span class="hljs-string">'data'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">data</span></span></span><span class="hljs-function">) </span></span>{
        <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Got data: '</span></span>, data);

        sockets.forEach(<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">otherSocket</span></span></span><span class="hljs-function">) </span></span>{
            <span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (otherSocket !== socket) {
                otherSocket.write(data);
            }
        });
    });

    <span class="hljs-comment"><span class="hljs-comment">// 新增代码</span></span>
    socket.on(<span class="hljs-string"><span class="hljs-string">'close'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
        <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'A client connection closed'</span></span>);
        <span class="hljs-keyword"><span class="hljs-keyword">var</span></span> index = sockets.indexOf(socket);
        sockets.splice(index, <span class="hljs-number"><span class="hljs-number">1</span></span>);
    });
});

server.on(<span class="hljs-string"><span class="hljs-string">'error'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">err</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server error: '</span></span>, err.message);
});

server.on(<span class="hljs-string"><span class="hljs-string">'close'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Server closed'</span></span>);
});

server.listen(<span class="hljs-number"><span class="hljs-number">8080</span></span>);
</code></pre><h3 id="labdoc-header-7">2.3 简易聊天室客户端</h3>
<p>聊天室的服务端功能基本就实现了，下面我们来写一个简单的客户端吧：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// chatClient.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> net = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">'net'</span></span>);

process.stdin.resume();
process.stdin.setEncoding(<span class="hljs-string"><span class="hljs-string">'utf8'</span></span>);

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> client = net.connect({ <span class="hljs-attr"><span class="hljs-attr">port</span></span>: <span class="hljs-number"><span class="hljs-number">8080</span></span> }, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Connected to server'</span></span>);

    <span class="hljs-comment"><span class="hljs-comment">// 获取输入的字符串</span></span>
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'input: '</span></span>);
    process.stdin.on(<span class="hljs-string"><span class="hljs-string">'data'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">data</span></span></span><span class="hljs-function">) </span></span>{
        <span class="hljs-comment"><span class="hljs-comment">// 发送输入的字符串到服务器</span></span>
        <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'input: '</span></span>);
        client.write(data);

        <span class="hljs-comment"><span class="hljs-comment">// 输入 'close' 字符串时关闭连接</span></span>
        <span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (data === <span class="hljs-string"><span class="hljs-string">'close\n'</span></span>) {
            client.end();
        }
    });
});

<span class="hljs-comment"><span class="hljs-comment">// 获取服务端发送过来的数据</span></span>
client.on(<span class="hljs-string"><span class="hljs-string">'data'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">data</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Other user\'s input'</span></span>, data.toString());
});

client.on(<span class="hljs-string"><span class="hljs-string">'end'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Disconnected from server'</span></span>);
    <span class="hljs-comment"><span class="hljs-comment">// 退出客户端程序</span></span>
    process.exit();
});
</code></pre><p>客户端中用到了process这个模块，process是一个Node.js的全局模块，可以在任何地方直接使用而无需通过require方法引入。process模块允许你获得或者修改当前Node.js进程的设置。<code>process.stdin</code>用于获取来自标准输入的可读流（Readable Stream）。</p><p>现在来运行这个聊天室吧：</p><pre><code class="hljs ruby">$ <span class="hljs-keyword">node</span> <span class="hljs-title">chatServer</span>.js
</code></pre><p>在打开多个终端窗口，运行：</p><pre><code class="hljs ruby">$ <span class="hljs-keyword">node</span> <span class="hljs-title">chatClient</span>.js
</code></pre><p>然后在任意运行的客户端输入字符串并按回车键，会在服务端和其他客户端看到这个客户端的输入内容。这样就实现了一个简单的聊天室了^_^。</p><h3 id="labdoc-header-8">2.4 UDP Server</h3>
<p>UDP和TCP类似，通过<code>dgram.createSocket</code>创建服务。</p><p>UDP服务器：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// udpServer.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> dgram = <span class="hljs-built_in"><span class="hljs-built_in">require</span></span>(<span class="hljs-string"><span class="hljs-string">"dgram"</span></span>);

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> server = dgram.createSocket(<span class="hljs-string"><span class="hljs-string">"udp4"</span></span>);

server.on(<span class="hljs-string"><span class="hljs-string">"error"</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">err</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">"server error:\n"</span></span> + err.stack);
    server.close();
});

<span class="hljs-comment"><span class="hljs-comment">// 接收来自客户端的消息</span></span>
server.on(<span class="hljs-string"><span class="hljs-string">"message"</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">msg, rinfo</span></span></span><span class="hljs-function">) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">"server got: "</span></span> + msg.toString() + <span class="hljs-string"><span class="hljs-string">" from "</span></span> + rinfo.address + <span class="hljs-string"><span class="hljs-string">":"</span></span> + rinfo.port);
});

<span class="hljs-comment"><span class="hljs-comment">// 监听服务</span></span>
server.on(<span class="hljs-string"><span class="hljs-string">"listening"</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-keyword"><span class="hljs-keyword">var</span></span> address = server.address();
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">"server listening on "</span></span> + address.address + <span class="hljs-string"><span class="hljs-string">":"</span></span> + address.port);
});

server.bind(<span class="hljs-number"><span class="hljs-number">41234</span></span>);
<span class="hljs-comment"><span class="hljs-comment">// server listening 0.0.0.0:41234</span></span>
</code></pre><p>UDP客户端：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// udpClient.js</span></span>

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> dgram = <span class="hljs-built_in">require</span>(<span class="hljs-string"><span class="hljs-string">'dgram'</span></span>);

<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> client = dgram.createSocket(<span class="hljs-string"><span class="hljs-string">'udp4'</span></span>);
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> <span class="hljs-keyword">message</span> = <span class="hljs-keyword">new</span> Buffer(<span class="hljs-string"><span class="hljs-string">'hello bestqd'</span></span>);

client.send(<span class="hljs-keyword">message</span>, <span class="hljs-number"><span class="hljs-number">0</span></span>, <span class="hljs-keyword">message</span>.length, <span class="hljs-number"><span class="hljs-number">41234</span></span>, <span class="hljs-string"><span class="hljs-string">'localhost'</span></span>, <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-params"><span class="hljs-function">(<span class="hljs-params">err, bytes</span>)</span></span><span class="hljs-function"> </span><span class="hljs-comment">{
    client.close();
}</span>);</span>
</code></pre><p>发送的消息必须通过Buffer创建。</p><p>然后运行服务端：</p><pre><code class="hljs ruby">$ <span class="hljs-keyword">node</span> <span class="hljs-title">udpServer</span>.js
</code></pre><p>再运行客户端：</p><pre><code class="hljs ruby">$ <span class="hljs-keyword">node</span> <span class="hljs-title">udpClient</span>.js
</code></pre><p>此时，服务端就会收到来自客户端的消息:</p><pre><code class="hljs css"><span class="hljs-selector-tag"><span class="hljs-selector-tag">server</span></span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">got</span></span>: <span class="hljs-selector-tag"><span class="hljs-selector-tag">hello</span></span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">bestqd</span></span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">from</span></span> 127<span class="hljs-selector-class"><span class="hljs-selector-class">.0</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.0</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.1</span></span><span class="hljs-selector-pseudo"><span class="hljs-selector-pseudo">:59393</span></span>
</code></pre><p>Node.js基础的网络编程就讲到这里了。</p><h2 id="labdoc-header-9">三、实验总结</h2>
<ol>
<li>作为web服务器软件，Node.js提供了<code>net</code>模块用于tcp通信，<code>dgram</code>模块用于udp通信</li>
<li>net.createServer()用于创建tcp监听服务器，net.connect()用于客户端连接tcp服务器</li>
<li><code>dgram</code>模块通过dgram.createSocket()创建udp socket,通过bind()监听特定端口，通过send()向特定socket发送信息 </li>
</ol>
<h2 id="labdoc-header-10">四、课后作业</h2>
<p>请你用Node.js <code>net</code>模块实现一个下载器，从预先确定的url中下载文件并保存到本地。此作业可能涉及到一些未讲过的知识，请自行查阅资料解决。</p><h2 id="labdoc-header-11">五、参考链接</h2>
<ul>
<li><a href="https://nodejs.org/api/net.html" target="_blank">https://nodejs.org/api/net.html</a></li>
<li><a href="https://nodejs.org/api/dgram.html" target="_blank">https://nodejs.org/api/dgram.html</a></li>
</ul>
</div>
</body>
</html>